//
//  SimpleWebImageManager.m
//  SimpleWebImage
//
//  Created by Jiang on 2019/8/26.
//  Copyright © 2019 SilverFruity. All rights reserved.
//

#import "SimpleWebImageManager.h"
#import <CommonCrypto/CommonCrypto.h>

@interface SimpleWebImageManager() <NSURLSessionDelegate>
{
    NSURLSession * _session;
}
@end

@implementation SimpleWebImageManager
+ (instancetype)shareInstance{
    static SimpleWebImageManager *_instance = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        _instance = [SimpleWebImageManager new];;
    });
    return _instance;
}

- (instancetype)init
{
    self = [super init];
    self.operationPool = [SimpleImageOperationPool new];
    self.diskCache = [SimpleDiskCache new];
    self.memoryCache = [SimpleMemoryCache new];
    NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
    _session = [NSURLSession sessionWithConfiguration:configuration delegate:self delegateQueue:[NSOperationQueue new]];
    
    return self;
}
- (SimpleImageOperation *)loadImageWithUrl:(NSURL *)url
                                  progress:(void (^)(double progress, NSURL *url))progress
                                  complete:(void (^)(UIImage *image,NSURL *url,NSError *error))complete{
    if (url == nil) {
        return nil;
    }
    if ([url isKindOfClass:[NSString class]]) {
        url = [NSURL URLWithString:(NSString *)url];
    }
    SimpleImageOperation *operation = [SimpleImageOperation new];
    operation.progressBlock = progress;
    operation.completeBlock = complete;
    NSString *key = [self cacheKeyForUrl:url];
    UIImage *image = [self.memoryCache imageForKey:key];
    if (image) {
        operation.completeBlock(image, url, nil);
        return operation;
    }
    
    NSArray *ops = [self.operationPool operationsForKey:key];
    if (ops) {
        [self.operationPool addOperation:operation forKey:key];
        return operation;
    }
    [self.operationPool addOperation:operation forKey:key];
    
    image = [self.diskCache imageForKey:key];
    if (image) {
        dispatch_async(dispatch_get_global_queue(0, 0), ^{
            [self compressWithImage:image handler:^(UIImage *result) {
                // 写入内存缓存
                [self.memoryCache saveImage:result forKey:key];
                dispatch_async(dispatch_get_main_queue(), ^{
                    [self invocatoinOperationsForKey:key image:image url:url error:nil];
                });
            }];
        });
        return operation;
    }
    
    NSURLSessionDownloadTask *task = [_session downloadTaskWithURL:url];
    [task resume];
    return operation;
}

- (void)invocatoinOperationsForKey:(NSString *)key image:(UIImage *)image url:(NSURL *)url error:(NSError *)error{
    //遍历当前图片相关操作
    for (SimpleImageOperation *operation in [self.operationPool operationsForKey:key]) {
        if (!operation.isCancel && operation.completeBlock) {
            operation.completeBlock(image, url, error);
        }
    }
    //移除图片加载操作
    [self.operationPool removeAllOperationsForKey:key];
}

- (void)compressWithImage:(UIImage *)image handler:(void(^)(UIImage *result))handler{
    if (!image) {
        handler(nil);
        return;
    }
    //解码
    CGSize size = image.size;
    UIGraphicsBeginImageContextWithOptions(size, NO, 0);
    CGContextRef ctx = UIGraphicsGetCurrentContext();
    CGContextSetFillColorWithColor(ctx, [UIColor clearColor].CGColor);
    CGRect rect = CGRectMake(0, 0, size.width, size.height);
    CGContextFillRect(ctx, rect);
    [image drawInRect:rect];
    UIImage *result = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    handler(result);
}

- (NSString *)cacheKeyForUrl:(NSURL *)url{
    if ([url isKindOfClass:[NSString class]]) {
        url = [NSURL URLWithString:(NSString *)url];
    }
    const char *cString = [url.absoluteString UTF8String];
    unsigned char result[CC_MD5_DIGEST_LENGTH];
    CC_MD5(cString, (CC_LONG)strlen(cString), result);
    NSMutableString *md5Result = [[NSMutableString alloc]init];
    for (int i = 0;i < CC_MD5_DIGEST_LENGTH; i++) {
        [md5Result  appendFormat:@"%02x",result[i]];
    }
    return md5Result;
}

- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite{
    dispatch_async(dispatch_get_main_queue(), ^{
        NSString *key  = [self cacheKeyForUrl:downloadTask.currentRequest.URL];
        for (SimpleImageOperation *op in [self.operationPool operationsForKey:key]) {
            if (op.progressBlock) {
                op.progressBlock((double)totalBytesWritten / (double)totalBytesWritten, downloadTask.currentRequest.URL);
            }
        }
    });
}

- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location{
    NSString *key  = [self cacheKeyForUrl:downloadTask.currentRequest.URL];
    UIImage *image = [UIImage imageWithContentsOfFile:location.path];
    [self compressWithImage:image handler:^(UIImage *result) {
        // 保存到本地
        [self.diskCache saveImage:result forKey:key];
        // 写入缓存
        [self.memoryCache saveImage:result forKey:key];
        dispatch_async(dispatch_get_main_queue(), ^{
            [self invocatoinOperationsForKey:key image:result url:downloadTask.currentRequest.URL error:nil];
        });
    }];
}

- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(nullable NSError *)error{
    NSString *key  = [self cacheKeyForUrl:task.currentRequest.URL];
    dispatch_async(dispatch_get_main_queue(), ^{
        [self invocatoinOperationsForKey:key image:nil url:task.currentRequest.URL error:error];
    });
}

@end


